﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using FDSimpleModelGenerator.Common;
using FDSimpleModelGenerator.Common.Enums;
using FDSimpleModelGenerator.Common.HtmlConvert;
using FDSimpleModelGenerator.Common.Mvc;
using FDSimpleModelGenerator.Common.Mvc.PageModels;
using FDSimpleModelGenerator.Entities;
using FDSimpleModelGenerator.Entities.Enums;
using FDSimpleModelGenerator.Entities.Exceptions;
using FDSimpleModelGenerator.Entities.Histories;
using FDSimpleModelGenerator.IServices;
using FDSimpleModelGenerator.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace FDSimpleModelGenerator.Pages
{
    /// <summary>
    /// 创建模型
    /// </summary>
    [Authorize]
    public class IndexModel : BasicModel
    {
        private readonly IEnumerable<IGenerateModelService> _generateModelServices;
        private IGenerateModelService _generateModelService;
        private readonly IWebHostEnvironment _hostingEnvironment;
        private readonly string _saveFolderName = "genresults";
        private readonly string _saveTableFolderName = "gentableresults";
        private readonly IExceptionThrowFactory _exceptionThrowFactory;
        private readonly IClassTemplateService _classTemplateService;
        private readonly IUserGenericHistoryService _userGenericHistoryService;
        private readonly ICache _cache;
        private readonly IEnumerable<ILanguageSymbolHtml> _languageSymbolHtmls;

        /// <summary>
        /// 模板列表
        /// name:,value:fileName,code:dataType
        /// </summary>
        public IList<CommonModel<string, int>> Templates { get; private set; }

        /// <summary>
        /// 数据库类型
        /// </summary>
        public IList<NameValue<string>> DatabaseTypes { get; private set; }

        private readonly string DbTypeCacheKey = "dbType_cache_for_user";
        private readonly string UserDbTypeCacheKey = "user_dbType_cache_for_user"; // 补上用户id

        public IndexModel(IEnumerable<IGenerateModelService> generateModelServices, IWebHostEnvironment hostingEnvironment,
            IExceptionThrowFactory exceptionThrowFactory, IClassTemplateService classTemplateService, ICache cache,
            IUserGenericHistoryService userGenericHistoryService, IEnumerable<ILanguageSymbolHtml> languageSymbolHtmls)
        {
            _languageSymbolHtmls = languageSymbolHtmls;
            var user = UserContext.Current.Context.User;
            DbTypeCacheKey = $"{DbTypeCacheKey}{user.Identity.Name}";
            UserDbTypeCacheKey = $"{UserDbTypeCacheKey}{user.Identity.Name}";
            _cache = cache;
            _exceptionThrowFactory = exceptionThrowFactory;
            _generateModelServices = generateModelServices;
            ChangeGenerateModelService();
            _hostingEnvironment = hostingEnvironment;
            _classTemplateService = classTemplateService;
            _userGenericHistoryService = userGenericHistoryService;
            Init();
        }

        /// <summary>
        /// 更改服务类型
        /// </summary>
        private void ChangeGenerateModelService()
        {
            var dbType = CacheManager.Default.Get<DbType>(DbTypeCacheKey);
            _generateModelService = _generateModelServices.FirstOrDefault(s => s.DbType == dbType);
            if (_generateModelService == null)
                _exceptionThrowFactory.Throw<ServiceConfigException>($"{nameof(IGenerateModelService)} was not register for {dbType}");
        }

        private void Init()
        {
            //var path = Path.Combine(_hostingEnvironment.WebRootPath, "Templates");
            //Templates = Directory.GetFiles(path, "*.fdtpl").Select(t =>
            //    new NameValue<string> { Name = Path.GetFileNameWithoutExtension(t), Value = Path.GetFileName(t) }).ToList();
            Templates = _classTemplateService.GetList().Select(c => new CommonModel<string, int> { Name = c.Name, Value = c.FileName, Code = c.DataType }).ToList();

            var dbTypes = EnumUtils.GetEnumList<DbType, int>();
            DatabaseTypes = dbTypes.Select(p => new NameValue<string>
            {
                Name = p.Name,
                Value = p.Value.ToString()
            }).ToList();
        }

        /// <summary>
        /// 显示页面
        /// </summary>
        public void OnGet()
        {
        }

        /// <summary>
        /// Post 生成模型
        /// </summary>
        /// <returns></returns>
        public async Task<IActionResult> OnPostGenerate([FromBody]GenerateModel model)
        {
            var filePath = Path.Combine(_hostingEnvironment.WebRootPath, "Templates", model.TemplateFileName);
            var template = System.IO.File.ReadAllText(filePath, Encoding.UTF8);
            var tables = model.TableName.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            var dbConfig = new DbConfig
            {
                Database = model.Database,
                DbType = model.DbType,
                Name = model.DbType.ToString(),
                Port = model.Port.ToString(),
                Password = HttpUtility.UrlDecode(model.Password), //"DX.net123!@#",
                ServerName = model.ServerName, //"192.168.50.79",
                UserName = model.UserId
            };
            SaveDbTypeConfig(model.DbType, model);
            var result = new List<GenerateTableModel>();
            foreach (var tableName in tables)
            {
                result.Add(await GenTable(dbConfig, tableName, template, Path.GetExtension(model.TemplateName), model.Namespace.Trim(),
                     model.LanguageDataType, model.FirstCharFormat == 0));
            }

            return new JsonResult(ApiResult.Success(result));
        }

        /// <summary>
        /// 生成表模型
        /// </summary>
        /// <param name="dbConfig"></param>
        /// <param name="tableName"></param>
        /// <param name="template"></param>
        /// <param name="@namespace"></param>
        /// <param name="propertyFirstCharLower"></param>
        /// <param name="fileExt"></param>
        /// <param name="languageDataType"></param>
        /// <returns></returns>
        private async Task<GenerateTableModel> GenTable(DbConfig dbConfig, string tableName, string template, string fileExt, string @namespace, LanguageDataType languageDataType, bool propertyFirstCharLower)
        {
            fileExt = fileExt.IsNullOrEmpty() ? ".cs" : fileExt;
            var className = TableFormatter.FormatClassName(tableName);
            var fileName = $"{className}{fileExt}"; // 因为cs文件不能下载
            var pathSave = $"{_saveFolderName}/{UserName}";
            var savePath = Path.Combine(_hostingEnvironment.WebRootPath, pathSave, fileName);
            FileSystemUtil.CreateIfDirNotExists(Path.Combine(_hostingEnvironment.WebRootPath, pathSave));
            var result = await _generateModelService.GenerateAsync(dbConfig, tableName, template, @namespace, languageDataType, propertyFirstCharLower);

            System.IO.File.WriteAllText(savePath, result, new UTF8Encoding(false));

            var tmp = _languageSymbolHtmls.First(h => h.LanguageDataType == languageDataType).ReplaceClsType(result); //new CSharpSymbolHtml().ReplaceClsType(result);

            var res = new GenerateTableModel
            {
                TableName = tableName,
                SourceContent = result,
                HtmlContent = tmp,
                FileLink = fileName
            };
            await _userGenericHistoryService.AddAsync(new UserGenericHistory
            {
                CreateTime = DateTime.Now,
                FileName = $"{pathSave}/{fileName}",
                ShortFileName = fileName,
                GenericType = GenericType.Model,
                IsEnable = true,
                UserId = UserId,
                Ip = HttpContext.RequestIp() //Request.HttpContext.Connection.RemoteIpAddress.ToString()
            });
            return res;
        }

        /// <summary>
        /// 下载文件
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="type">下载类型：0模型，1表sql</param>
        /// <returns></returns>
        public IActionResult OnGetDownload(string fileName, int type = 0)
        {
            var saveFolderName = type == 0 ? _saveFolderName : _saveTableFolderName;
            var pathSave = $"{saveFolderName}/{UserName}";
            var savePath = Path.Combine(_hostingEnvironment.WebRootPath, pathSave, fileName);
            if (!System.IO.File.Exists(fileName))
            {
                return File(new FileStream(savePath, FileMode.Open, FileAccess.Read), "application/octet-stream",
                    fileName);
            }

            return NotFound(fileName);
        }

        /// <summary>
        /// 修改数据库类型
        /// </summary>
        /// <param name="dbType"></param>
        /// <returns></returns>
        public IActionResult OnPostChangeDbType(int dbType)
        {
            var type = (DbType)dbType;
            ChangeCurrentDbType(type);
            var config = GetDbTypeConfig(type);

            return new JsonResult(config == null ? ApiResult.Failure(ApiResultCode.Failure, "不存在配置信息") : ApiResult.Success(config));//Content($"DatabaseType:{dbType},{type}");
        }

        private void ChangeCurrentDbType(DbType type)
        {
            CacheManager.Default.Set(DbTypeCacheKey, type, TimeSpan.FromHours(1));
            ChangeGenerateModelService();
        }

        private void SaveDbTypeConfig(DbType dbType, GenerateModel generateModel)
        {
            _cache.Set($"{UserDbTypeCacheKey}{dbType}", generateModel, TimeSpan.FromHours(1));
        }

        private GenerateModel GetDbTypeConfig(DbType dbType)
        {
            return _cache.Get<GenerateModel>($"{UserDbTypeCacheKey}{dbType}");
        }
    }
}
